/**
  ***********************************************************************************************************
  * @file           : bsp_can.c
  * @brief          : can通信BSP源文件
  ***********************************************************************************************************
  * @attention
  * 通过can_config_filter_STD函数将指定过滤器组配置为指定can外设,指定的FIFO队列,
	(16位宽标准帧,数据帧模式)
  * 使用can_send_msg函数使用指定can外设对指定的ID发送指定长度的报文
  * 使用can_get_recived_msg函数从指定can外设,指定的FIFO队列获取报文信息
  ***********************************************************************************************************
  * @needToDo
  * 使用时先通过can_init函数初始化can外设 			@(已经在can_motor_user.c的初始化中调用)
  * 请在本文件中定义的HAL_CAN_RxFifo0MsgPendingCallback和HAL_CAN_RxFifo1MsgPendingCallback
	函数中完善can报文接收后的信息提取与转存(需要视具体过滤器配置以及can线和FIFO的选择自行更改)
  ***********************************************************************************************************
  */

#include "bsp_can.h"

/*	外部变量&头文件链接区 BEGIN	*/
#include "Can_Motor_drv.h"
#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "can_motor_task.h"
#include "can_motor_user.h"

//消息队列,应对can报文回调的线程安全
extern can_msg_queue_t queue_can1_fifo0[can1_fifo0_motor_cnt];
extern can_msg_queue_t queue_can2_fifo0[can2_fifo0_motor_cnt];
/*	外部变量&头文件链接区 END	*/


/***********************函数定义区**********************/


/**
 * @brief 初始化can外设
 * @param hcan 要打开的can外设    @args &hcan1 或者 &hcan2
 */
void can_init(CAN_HandleTypeDef* hcan)
{
	//开启hcan对应的can外设
	HAL_CAN_Start(hcan);
	/* 允许hcan对应can外设的can报文接收中断(FIFO0和FIFO1接收中断都打开) */
	__HAL_CAN_ENABLE_IT(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
    __HAL_CAN_ENABLE_IT(hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
	/* 开启can报文挂起中断 */
	HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
	HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO1_MSG_PENDING);
}


/**
 * @brief 使用指定的can外设,以标准ID,数据帧模式来发送can报文
 * @param hcan 		使用的can外设				@args &hcan1 或者 &hcan2
 * @param ID 		发送can报文的地址			@args 0x000~0x7FF
 * @param Data 		指向所要发送报文数据的指针	@args 0x000~0x7FF
 * @param Length 	报文数据长度				@args 0~8
 * @return uint8_t 	执行状态
 */
uint8_t can_send_msg(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *Data, uint16_t Length)
{
	CAN_TxHeaderTypeDef tx_header;
    uint32_t used_mailbox;
    //检测传参是否正确
    assert_param(hcan != NULL);
	
	//设置ID
    tx_header.StdId = ID;
    tx_header.ExtId = 0;
	//标准ID,数据帧模式
    tx_header.IDE = CAN_ID_STD;
    tx_header.RTR = CAN_RTR_DATA;
	//设置报文数据长度
    tx_header.DLC = Length;
    return (HAL_CAN_AddTxMessage(hcan, &tx_header, Data, &used_mailbox));
}


/**
 * @brief 从指定的can外设,指定的FIFO队列中获取接收到的报文,并将报文数据存入用户指定的结构体
 * @param hcan 		使用的can外设				@args &hcan1 或者 &hcan2
 * @param RxFIFO	can过滤器队列				@args CAN_FILTER_FIFO0 或者 CAN_FILTER_FIFO1
 * @param DataBuf	接收报文数据的结构体指针		
 * @param 
 */
void can_get_recived_msg(CAN_HandleTypeDef* hcan,uint32_t RxFIFO,can_recive_msg_t* DataBuf)
{
	//获取报文
	CAN_RxHeaderTypeDef can_rx_header = {0};
	HAL_CAN_GetRxMessage(hcan,RxFIFO,&can_rx_header,DataBuf->data);
	//提取报文信息
	DataBuf->DLC = can_rx_header.DLC;	//获取报文数据长度
	DataBuf->StdId = can_rx_header.StdId;	//获取报文的地址
	DataBuf->ExtId = can_rx_header.ExtId;
	DataBuf->IDE = can_rx_header.IDE;
	DataBuf->RTR = can_rx_header.RTR;
}


/**
 * @brief 以标准帧模式配置CAN的过滤器(,默认为数据帧,不包含遥控帧)
 * @param hcan 			CAN句柄指针  @args &hcan1 或者 &hcan2
 * @param filter_num 	过滤器编号	 @args 0-27, 其中CAN1:0-13, CAN2:14-27
 * @param IDx 			ID			 @args 0x000 ~ 0x7ff(标准帧)
 * @param MASKx 		IDx对应掩码	 @args 11位的二进制数(标准帧),想要匹配IDx的哪位就把哪位置1
 * @param Rx_FIFO 		接收FIFO 	 @args CAN_FILTER_FIFO0 或 CAN_FILTER_FIFO1
 */
void can_config_filter_STD(CAN_HandleTypeDef *hcan,
						uint32_t ID1,uint32_t ID2,uint32_t MASK1, uint32_t MASK2, 
						uint32_t filter_num, uint32_t Rx_FIFO)
{
    CAN_FilterTypeDef can_filter = {0};
	//基础固定配置
	can_filter.SlaveStartFilterBank = 14;				//can2的过滤器从14开始(14~28)
	can_filter.FilterMode = CAN_FILTERMODE_IDMASK;		//掩码模式
	can_filter.FilterScale = CAN_FILTERSCALE_16BIT;		//寄存器位宽为16BIT
	can_filter.FilterActivation = CAN_FILTER_ENABLE;	//使能过滤器
	//处理过滤器编号和选择对应的报文FIFO
    can_filter.FilterBank = filter_num;					//过滤器编号
	can_filter.FilterFIFOAssignment = Rx_FIFO;			//报文队列
	
	uint32_t id1_reg = (ID1 & 0x7FF) << 5;          // 确保ID不超过11位
    uint32_t mask1_reg = (MASK1 & 0x7FF) << 5;      
    mask1_reg |= 0x10; // 设置IDE和RTR的掩码位为1和0（0x10 = 00010000b）
    uint32_t id2_reg = (ID2 & 0x7FF) << 5;
    uint32_t mask2_reg = (MASK2 & 0x7FF) << 5;
    mask2_reg |= 0x10; // 同上
	
	
    /* 配置过滤器寄存器 */
    can_filter.FilterIdHigh = id1_reg & 0xFFFF;             // 第一个ID的高16位部分
    can_filter.FilterMaskIdHigh = mask1_reg & 0xFFFF;       // 第一个掩码的低16位部分
    can_filter.FilterIdLow = id2_reg & 0xFFFF;              // 第二个ID的高16位部分
    can_filter.FilterMaskIdLow = mask2_reg & 0xFFFF;        // 第二个掩码的低16位部分
	
	//配置过滤器组
	HAL_CAN_ConfigFilter(hcan,&can_filter);
}


//can接收中断回调函数
/**
 * @brief FIFO0的中断回调
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan == &hcan1)
	{
		//临时定义一个can_recive_msg_t结构体,存储接收到的报文数据
		can_recive_msg_t rx_data = {0};
		can_get_recived_msg(&hcan1,CAN_FILTER_FIFO0,&rx_data);
		
		/*	can报文信息提取与转存 BEGIN	*/
		{
			//底盘4个3508电机
			for(uint8_t i = 0; i < can1_fifo0_motor_cnt; ++i)
			{
				if(rx_data.StdId == queue_can1_fifo0[i].stdID)
				{
					//将接收到的数据放入队列
					osMessageQueuePut(queue_can1_fifo0[i].que,&rx_data,0,0);
				}
			}
		}
		/*	can报文信息提取与转存 END	*/
	}
	
	else if(hcan == &hcan2)
	{
		can_recive_msg_t rx_data = {0};
		can_get_recived_msg(&hcan2,CAN_FILTER_FIFO0,&rx_data);
		
		/*	can报文信息提取与转存 BEGIN	*/
		{
			//上层5个3508电机
			for(uint8_t i = 0; i < can2_fifo0_motor_cnt; ++i)
			{
				if(rx_data.StdId == queue_can2_fifo0[i].stdID)
				{
					//将接收到的数据放入队列
					osMessageQueuePut(queue_can2_fifo0[i].que,&rx_data,0,0);
				}
			}
		}
		/*	can报文信息提取与转存 END	*/
	}
	
}


/**
 * @brief FIFO1的中断回调
 */
#if 0
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan == &hcan1)
	{
		//临时定义一个can_recive_msg_t结构体,存储接收到的报文数据
		can_recive_msg_t call_back_recived_data = {0};
		can_get_recived_msg(&hcan1,CAN_FILTER_FIFO1,&call_back_recived_data);
		
		/*	can报文信息提取与转存 BEGIN	*/

		/*	can报文信息提取与转存 END	*/
	}
	
	if(hcan == &hcan2)
	{
		can_recive_msg_t call_back_recived_data = {0};
		can_get_recived_msg(&hcan2,CAN_FILTER_FIFO1,&call_back_recived_data);
		
		/*	can报文信息提取与转存 BEGIN	*/

		/*	can报文信息提取与转存 END	*/
	}
}
#endif




